/******************************************************************************* * Copyright (c) 2015 Jeff Martin. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public * License v3.0 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl.html * * Contributors: * Jeff Martin - initial API and implementation ******************************************************************************/ package cuchaz.enigma.bytecode; import java.util.Collection; import java.util.List; import java.util.Map; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import cuchaz.enigma.bytecode.accessors.*; public enum InfoType { Utf8Info(1, 0), IntegerInfo(3, 0), FloatInfo(4, 0), LongInfo(5, 0), DoubleInfo(6, 0), ClassInfo(7, 1) { @Override public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) { ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem()); gatherIndexTree(indices, editor, accessor.getNameIndex()); } @Override public void remapIndices(Map<Integer, Integer> map, ConstInfoAccessor entry) { ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem()); accessor.setNameIndex(remapIndex(map, accessor.getNameIndex())); } @Override public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem()); ConstInfoAccessor nameEntry = pool.getItem(accessor.getNameIndex()); return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag(); } }, StringInfo(8, 1) { @Override public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) { StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem()); gatherIndexTree(indices, editor, accessor.getStringIndex()); } @Override public void remapIndices(Map<Integer, Integer> map, ConstInfoAccessor entry) { StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem()); accessor.setStringIndex(remapIndex(map, accessor.getStringIndex())); } @Override public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem()); ConstInfoAccessor stringEntry = pool.getItem(accessor.getStringIndex()); return stringEntry != null && stringEntry.getTag() == Utf8Info.getTag(); } }, FieldRefInfo(9, 2) { @Override public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) { MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem()); gatherIndexTree(indices, editor, accessor.getClassIndex()); gatherIndexTree(indices, editor, accessor.getNameAndTypeIndex()); } @Override public void remapIndices(Map<Integer, Integer> map, ConstInfoAccessor entry) { MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem()); accessor.setClassIndex(remapIndex(map, accessor.getClassIndex())); accessor.setNameAndTypeIndex(remapIndex(map, accessor.getNameAndTypeIndex())); } @Override public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem()); ConstInfoAccessor classEntry = pool.getItem(accessor.getClassIndex()); ConstInfoAccessor nameAndTypeEntry = pool.getItem(accessor.getNameAndTypeIndex()); return classEntry != null && classEntry.getTag() == ClassInfo.getTag() && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); } }, // same as FieldRefInfo MethodRefInfo(10, 2) { @Override public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) { FieldRefInfo.gatherIndexTree(indices, editor, entry); } @Override public void remapIndices(Map<Integer, Integer> map, ConstInfoAccessor entry) { FieldRefInfo.remapIndices(map, entry); } @Override public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { return FieldRefInfo.subIndicesAreValid(entry, pool); } }, // same as FieldRefInfo InterfaceMethodRefInfo(11, 2) { @Override public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) { FieldRefInfo.gatherIndexTree(indices, editor, entry); } @Override public void remapIndices(Map<Integer, Integer> map, ConstInfoAccessor entry) { FieldRefInfo.remapIndices(map, entry); } @Override public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { return FieldRefInfo.subIndicesAreValid(entry, pool); } }, NameAndTypeInfo(12, 1) { @Override public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) { NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem()); gatherIndexTree(indices, editor, accessor.getNameIndex()); gatherIndexTree(indices, editor, accessor.getTypeIndex()); } @Override public void remapIndices(Map<Integer, Integer> map, ConstInfoAccessor entry) { NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem()); accessor.setNameIndex(remapIndex(map, accessor.getNameIndex())); accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex())); } @Override public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem()); ConstInfoAccessor nameEntry = pool.getItem(accessor.getNameIndex()); ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex()); return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag() && typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); } }, MethodHandleInfo(15, 3) { @Override public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) { MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem()); gatherIndexTree(indices, editor, accessor.getTypeIndex()); gatherIndexTree(indices, editor, accessor.getMethodRefIndex()); } @Override public void remapIndices(Map<Integer, Integer> map, ConstInfoAccessor entry) { MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem()); accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex())); accessor.setMethodRefIndex(remapIndex(map, accessor.getMethodRefIndex())); } @Override public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem()); ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex()); ConstInfoAccessor methodRefEntry = pool.getItem(accessor.getMethodRefIndex()); return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag() && methodRefEntry != null && methodRefEntry.getTag() == MethodRefInfo.getTag(); } }, MethodTypeInfo(16, 1) { @Override public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) { MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem()); gatherIndexTree(indices, editor, accessor.getTypeIndex()); } @Override public void remapIndices(Map<Integer, Integer> map, ConstInfoAccessor entry) { MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem()); accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex())); } @Override public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem()); ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex()); return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); } }, InvokeDynamicInfo(18, 2) { @Override public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) { InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem()); gatherIndexTree(indices, editor, accessor.getBootstrapIndex()); gatherIndexTree(indices, editor, accessor.getNameAndTypeIndex()); } @Override public void remapIndices(Map<Integer, Integer> map, ConstInfoAccessor entry) { InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem()); accessor.setBootstrapIndex(remapIndex(map, accessor.getBootstrapIndex())); accessor.setNameAndTypeIndex(remapIndex(map, accessor.getNameAndTypeIndex())); } @Override public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem()); ConstInfoAccessor bootstrapEntry = pool.getItem(accessor.getBootstrapIndex()); ConstInfoAccessor nameAndTypeEntry = pool.getItem(accessor.getNameAndTypeIndex()); return bootstrapEntry != null && bootstrapEntry.getTag() == Utf8Info.getTag() && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); } }; private static Map<Integer, InfoType> m_types; static { m_types = Maps.newTreeMap(); for(InfoType type : values()) m_types.put(type.getTag(), type); } private int m_tag; private int m_level; private InfoType(int tag, int level) { m_tag = tag; m_level = level; } public int getTag() { return m_tag; } public int getLevel() { return m_level; } public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) { // by default, do nothing } public void remapIndices(Map<Integer, Integer> map, ConstInfoAccessor entry) { // by default, do nothing } public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { // by default, everything is good return true; } public boolean selfIndexIsValid(ConstInfoAccessor entry, ConstPoolEditor pool) { ConstInfoAccessor entryCheck = pool.getItem(entry.getIndex()); if(entryCheck == null) return false; return entryCheck.getItem().equals(entry.getItem()); } public static InfoType getByTag(int tag) { return m_types.get(tag); } public static List<InfoType> getByLevel(int level) { List<InfoType> types = Lists.newArrayList(); for(InfoType type : values()) if(type.getLevel() == level) types.add(type); return types; } public static List<InfoType> getSortedByLevel() { List<InfoType> types = Lists.newArrayList(); types.addAll(getByLevel(0)); types.addAll(getByLevel(1)); types.addAll(getByLevel(2)); types.addAll(getByLevel(3)); return types; } public static void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, int index) { // add own index indices.add(index); // recurse ConstInfoAccessor entry = editor.getItem(index); entry.getType().gatherIndexTree(indices, editor, entry); } private static int remapIndex(Map<Integer, Integer> map, int index) { Integer newIndex = map.get(index); if(newIndex == null) newIndex = index; return newIndex; } }